//
//  WMDataCache.m
//  WeightMaster
//
//  Created by sungeo on 15/8/14.
//  Copyright (c) 2015年 buddysoft. All rights reserved.
//

#import "WMDataCache.h"
#import "WMWeight.h"
#import "WMPhoto.h"
#import "WMPhotoCache.h"
#import <TMDiskCache.h>
#import <DateTools.h>
#import <NSObject+GLPubSub.h>

// 存储到本地缓存用的 key
static NSString * const WeightsKey = @"WeightsKey";

// 存储关联对象用到的 key
const void * AssociatedWeightRecord = @"associatedWeightRecord";

// 体重记录有改变时发送的消息 key
NSString * const WeightsChangedNote = @"WeightsChanged";
// 今日体重有改变时发送的消息
NSString * const LastWeightChangedNote = @"LatestWeightChanged";

// 数据同步定时器时间间隔
const NSInteger SyncingTimerFireInterval = 1;

@interface WMDataCache(){
    NSMutableArray * _internalWeights;
    NSCache * _profileAssetsCache;
    
    BDiCloudManager * _iCloudManager;
}

@end

@implementation WMDataCache

+ (instancetype)sharedInstance{
    static WMDataCache * sInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (sInstance == nil) {
            sInstance = [[WMDataCache alloc] init];
            [sInstance loadCachedWeights];
        }
    });
    
    return sInstance;
}

- (instancetype)init{
    if (self = [super init]) {
        _profileAssetsCache = [[NSCache alloc] init];
        _internalWeights = [NSMutableArray array];
        
        _iCloudManager = [[BDiCloudManager alloc] init];
        _iCloudManager.delegate = self;
        
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(CloudKitNotAvailable:) name:CloudKitNotAvailableNote object:_iCloudManager];
    }
    
    return self;
}

- (void)loadCachedWeights{
    id object = [[TMDiskCache sharedCache] objectForKey:WeightsKey];
    if (object && [object isKindOfClass:[NSArray class]]) {
        _internalWeights = (NSMutableArray *)[object mutableCopy];
        
        _internalWeights = [[WMHelper sortingWeightsByMeasuringDate:_internalWeights] mutableCopy];
    }
}

#pragma mark - Alert view delegate
static NSString * const LastAlertShownDateKey = @"lastAlertShownDate";
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex{
    if (buttonIndex == alertView.firstOtherButtonIndex) {
        // 去设置 iCloud
        NSURL * url = [NSURL URLWithString:@"prefs:root=CASTLE"];
        [[UIApplication sharedApplication] openURL:url];
    }else if(buttonIndex == alertView.cancelButtonIndex){
        // “以后再说”：设置两天后再提醒
        [[TMDiskCache sharedCache] setObject:[NSDate date] forKey:LastAlertShownDateKey];
    }
}

- (void)CloudKitNotAvailable:(NSNotification *)sender{
    id object = [[TMDiskCache sharedCache] objectForKey:LastAlertShownDateKey];
    if (object && [object isKindOfClass:[NSDate class]]) {
        NSDate * lastShownDate = (NSDate *)object;
        NSInteger days = [lastShownDate daysFrom:[NSDate date]];
        const NSInteger MinimalInterval = 2;
        if (days > - MinimalInterval) {
            // 2 天后才允许再次提示
            NSLog(@"%@ 天前才提醒过，暂不提醒（提醒间隔：%@）", @(days), @(MinimalInterval));
            return;
        }
    }
    
    dispatch_async(dispatch_get_main_queue(), ^{
        UIAlertView * av = [[UIAlertView alloc] initWithTitle:@"保存您的体重记录到 iCloud" message:@"打开后，应用会自动保存体重记录和照片到云端。" delegate:self cancelButtonTitle:@"以后再说" otherButtonTitles:@"去设置", nil];
        [av show];
    });
}


- (void)updateWeight:(WMWeight *)oldWeight withCloudWeight:(WMWeight *)newWeight{
    
    // 采用覆盖方式修改体重，覆盖照片和体重值
    BOOL oldProfileExist = oldWeight.profileUUID.length != 0;

    // 旧照片存在并跟新照片 UUID 不同时，删除旧照片
    if (oldProfileExist){
        BOOL newProfileExist = newWeight.profileUUID.length != 0;
        
        if(![oldWeight.profileUUID isEqualToString:newWeight.profileUUID] || ! newProfileExist) {
            
            [[WMPhotoCache sharedInstance] deleteImageWithUUID:oldWeight.profileUUID];
            NSLog(@"旧照片: %@, 新照片: %@", [oldWeight monthAndDayString], [newWeight monthAndDayString]);
        }
        
    }
    
    oldWeight.profileUUID = newWeight.profileUUID;
    oldWeight.value = newWeight.value;
    
    
    NSLog(@"更新体重记录");
}

#pragma mark - 添加或更新体重入口

- (BOOL)addWeight:(WMWeight *)newWeight fromCloud:(BOOL)fromCloud{
    if (fromCloud) {
        // 同步从云端得到的体重
        [self addCloudWeight:newWeight];
    }else{
        // 先处理体重中的图片
        [self saveLocalProfileImageForWeight:newWeight];
        
        // 本地新建体重
        [self addLocalCreatedWeight:newWeight];
    }
    
    _internalWeights = [[WMHelper sortingWeightsByMeasuringDate:_internalWeights] mutableCopy];
    
    // 缓存到本地
    [self syncDataToDisk];
    
    // 发布体重数据有更新消息
    [self publish:WeightsChangedNote];
    
    // 修改当天信息时，发布更新今日体重消息
    if ([newWeight isTheSameDayWith:[self latestWeight]]) {
        [self publish:LastWeightChangedNote];
    }

    return YES;
}

- (BOOL)addCloudWeight:(WMWeight *)newWeight{

    // 检查当日体重记录是否已经存在
    BOOL found = NO;
    const NSInteger count = _internalWeights.count;
    if (count > 0) {
        for (NSInteger i = count - 1; i >= 0; i --) {
            WMWeight * oldWeight = _internalWeights[i];
            if ([oldWeight isTheSameDayWith:newWeight]) {
                
                // 同一天已有记录，修改
                [self updateWeight:oldWeight withCloudWeight:newWeight];
                oldWeight.savedToICloud = @(YES);
                
                found = YES;
                
                break;
                
            }else if([oldWeight isEarlierThan:newWeight]){
                // 按时间先后顺序排列的记录，找到第一个小于新记录日期的，可以认为之前的都小于新纪录，
                // 所以之前的都不会等于新纪录，查询结束。
                break;
            }
        }
    }
    
    if (! found) {
        // 缓存到本地
        [_internalWeights addObject:newWeight];
    }
    
    return YES;
}

- (BOOL)addLocalCreatedWeight:(WMWeight *)newWeight{
    const NSInteger count = _internalWeights.count;
    
    BOOL found = NO;
    
    // 如果当天记录存在，修改；否则新增。
    if (count > 0) {
        WMWeight * latestWeight = _internalWeights[count - 1];
        if ([latestWeight isTheSameDayWith:newWeight]) {
            // 修改
            [self updateWeight:latestWeight withCloudWeight:newWeight];
            latestWeight.savedToICloud = @(NO);
            found = YES;
        }
    }
    
    if (found == NO) {
        // 新增
        [_internalWeights addObject:newWeight];
    }
    
    if (! [BDiCloudManager serviceReady]) {
        return NO;
    }
    
    // 将每次添加本地体重作为依次上传所有未上传的体重记录的时机
    [self uploadUnsavedWeights];
    
    return YES;
}

- (void)uploadUnsavedWeights{
    
    for (WMWeight * weight in _internalWeights) {
        if (weight.savedToICloud.boolValue == NO) {
            
            // 根据 ID 是否能查询到目标对象，来决定是修改还是新建体重记录
            CKRecordID * recordID = [[CKRecordID alloc] initWithRecordName:[weight weightUUID]];
            [_iCloudManager.privateDatabase fetchRecordWithID:recordID completionHandler:^(CKRecord * record, NSError * error){
                if (record == nil) {
                    // 未找到记录，新建
                    record = [weight convertToCKRecord];
                }else{
                    // 找到体重记录，更新旧的
                    [weight packingCKRecord:record];
                }
                
                // 上传
                [_iCloudManager addRecord:record];
            }];
        }
    }
}

- (void)saveLocalProfileImageForWeight:(WMWeight *)weight{
    UIImage * localImage = [weight localProfileImage];
    if (localImage) {
        if (weight.profileUUID.length == 0) {
            weight.profileUUID = [[NSUUID UUID] UUIDString];
        }
        
        [[WMPhotoCache sharedInstance] addImage:localImage withUUID:weight.profileUUID];
    }
}

- (NSArray *)weights{
    return [_internalWeights copy];
}

- (void)queryWeightsFromiCloud{
    [_iCloudManager queryRecordsWithType:WMWeightRecord];
}

- (void)deleteAllRecords{
    [_iCloudManager deleteDefaultRecordZone];
}

- (void)syncDataToDisk{
    TMDiskCache * cache = [TMDiskCache sharedCache];
    [cache setObject:_internalWeights forKey:WeightsKey];
}

- (WMWeight *)latestWeight{
    const NSInteger count = [_internalWeights count];
    if (count <= 0) {
        return nil;
    }else{
        return _internalWeights[count - 1];
    }
}

- (NSArray *)latest5Weights{
    NSArray * sorted = [WMHelper sortingWeightsByMeasuringDate:_internalWeights];
    const NSInteger Count = sorted.count;
    if (Count <= 5) {
        return sorted;
    }else{
        NSMutableArray * mutable = [NSMutableArray array];
        for (NSInteger i = Count - 5; i < Count; i ++) {
            [mutable addObject:sorted[i]];
        }
        
        return mutable;
    }
}

- (WMWeightRange)weightRange{
    return [WMHelper weightRangeForWeights:_internalWeights];
}

- (NSArray *)minAndMaxWeightObjects:(NSArray *)from{
    NSArray * sorted;
    if (from == nil) {
        sorted = [WMHelper sortingWeightsByValue:_internalWeights];
    }else{
        sorted = [WMHelper sortingWeightsByValue:from];
    }
    
    const NSInteger count = sorted.count;
    if (count > 0) {
        return [NSMutableArray arrayWithObjects:sorted[0], sorted[count - 1], nil];
    }else{
        return nil;
    }
}

- (WMWeight *)weightWithUUID:(NSString *)uuid{
    for (WMWeight * weight in _internalWeights) {
        if ([weight.profileUUID isEqualToString:uuid]) {
            return weight;
        }
    }
    
    return nil;
}

#pragma mark - BD iCloud delegate

// 查询记录成功
- (void)didReceiveRecords:(NSArray *)records{
    BOOL changed = NO;
    
    NSLog(@"从 CloudKit 查询到 %@ 条体重记录", @(records.count));
    _hasQueriedWeights = YES;
    
    for (CKRecord * record in records) {
        if ([record.recordType isEqualToString:WMWeightRecord]) {
            WMWeight * weight = [[WMWeight alloc] initFromiCloudRecordObject:record];
            if([self addWeight:weight fromCloud:YES]){
                changed = YES;
            }
        }
    }
    
    if (changed) {
        // 别忘了重新排序
        _internalWeights = [[WMHelper sortingWeightsByMeasuringDate:_internalWeights] mutableCopy];
    }
}

// 查询记录失败
- (void)queryRecordsFailedWithError:(NSError *)error{
    
}

// 添加（或修改）记录成功
- (void)successfullySavedRecord:(CKRecord *)record{
    if([record.recordType isEqualToString:WMWeightRecord]){
        WMWeight * weight = [self weightWithUUID:record.recordID.recordName];
        if (weight) {
            weight.savedToICloud = @(YES);
            [self syncDataToDisk];
            
            NSLog(@"保存体重到 CloudKit 成功: %@", [weight.measuringDate formattedDateWithStyle:NSDateFormatterShortStyle]);
        }
    }    
}

- (void)successfullyDeletedDefaultZone{
    [_internalWeights removeAllObjects];
    [self syncDataToDisk];
    NSLog(@"清空本地缓存");
}


@end
